package com.kmxd.ams.app.event.log;

import cn.hutool.core.util.ObjectUtil;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.client.event.log.DocumentLogEvent;
import com.kmxd.ams.client.event.log.VolumeLogEvent;
import com.kmxd.ams.client.logs.ILogArchiveSvc;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.enums.ArchOpEnum;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.logs.entity.LogArchive;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;

/**
 * 档案利用日志
 *
 * @author nickbi
 */
@Slf4j
@Component
@AllArgsConstructor
public class LogArchListener {
  private final ILogArchiveSvc logArchiveSvc;
  private final IDocumentSvc documentSvc;
  private final IVolumeSvc volumeSvc;

  @Async
  @TransactionalEventListener(fallbackExecution = true)
  public void documentLog(DocumentLogEvent event) {
    List<Document> documents = documentSvc.selectList(event.getReq());
    if (ObjectUtil.isEmpty(documents)) {
      return;
    }
    List<LogArchive> logList =
        documents.stream()
            .map(
                item -> {
                  ArchOpEnum op = event.getOp();
                  return op.getTypeList().stream()
                      .map(
                          type -> {
                            LogArchive log = ConvertUtil.toBean(item, LogArchive.class);
                            log.setId(null);
                            log.setType(type.getType().getType());
                            log.setTypeName(type.getType().getDesc());
                            log.setOpType(type.getOpType());
                            log.setOpTypeName(type.getOpTypeName());
                            log.setOp(event.getOp().getCode());
                            log.setOpName(event.getOp().getDesc());
                            log.setActionDescription(event.getContent());
                            log.setArchId(item.getId());
                            log.setTableId(event.getReq().getTableId());
                            log.setArchTypeId(event.getReq().getArchTypeId());
                            log.setArchTitle(item.getTitle());
                            log.setSecurity(item.getSecurity());
                            setUserInfo(event.getSaToken(), log);
                            setUserInfo(event.getSaToken(), log);
                            return log;
                          })
                      .collect(Collectors.toList());
                })
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
    logArchiveSvc.saveBatch(logList);
  }

  @Async
  @TransactionalEventListener(fallbackExecution = true)
  public void volumeLog(VolumeLogEvent event) {
    List<Volume> volumes = Lists.newArrayList();
    if (ObjectUtil.isNotEmpty(event.getReq().getVolIds())) {
      DynamicTableNameUtil.setTableName(event.getReq().getTableId());
      Set<Long> ids = IdUtil.split(event.getReq().getVolIds());
      volumes = volumeSvc.selectListByIds(ids);
    } else {
      volumes = volumeSvc.selectList(event.getReq());
    }
    if (ObjectUtil.isEmpty(volumes)) {
      return;
    }
    List<LogArchive> logList =
        volumes.stream()
            .map(
                item -> {
                  ArchOpEnum op = event.getOp();
                  return op.getTypeList().stream()
                      .map(
                          type -> {
                            LogArchive log = ConvertUtil.toBean(item, LogArchive.class);
                            log.setId(null);
                            log.setType(type.getType().getType());
                            log.setTypeName(type.getType().getDesc());
                            log.setOpType(type.getOpType());
                            log.setOpTypeName(type.getOpTypeName());
                            log.setOp(event.getOp().getCode());
                            log.setOpName(event.getOp().getDesc());
                            log.setActionDescription(event.getContent());
                            log.setArchId(item.getId());
                            log.setTableId(event.getReq().getTableId());
                            log.setArchTypeId(event.getReq().getArchTypeId());
                            log.setArchTitle(item.getTitle());
                            log.setSecurity(item.getSecurity());
                            setUserInfo(event.getSaToken(), log);
                            setUserInfo(event.getSaToken(), log);
                            return log;
                          })
                      .collect(Collectors.toList());
                })
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
    logArchiveSvc.saveBatch(logList);
  }

  private void setUserInfo(String saToken, LogArchive log) {
    log.setComId(SecurityUtil.getCropId(saToken));
    log.setFondsId(SecurityUtil.getFondsId(saToken));
    log.setUserId(SecurityUtil.getUserId(saToken));
    LoginUser loginUser = SecurityUtil.getLoginUser(saToken);
    log.setDeptId(Objects.requireNonNull(loginUser).getDeptId());
    log.setDeptName(loginUser.getDeptName());
    log.setRoleId(loginUser.getRoleId());
    log.setUserName(loginUser.getUsername());
    log.setUserCode(loginUser.getSysUser().getAccount());
    log.setOpTime(new Date());
    log.setIp(loginUser.getIpAddress());
  }
}
